package com.ruoyi.quartz.util

import com.ruoyi.common.utils.MyStringUtils
import com.ruoyi.common.utils.spring.SpringUtils
import com.ruoyi.quartz.domain.SysJob
import org.apache.commons.lang3.StringUtils
import java.lang.reflect.InvocationTargetException
import java.util.*

/**
 * 任务执行工具
 *
 * @author ruoyi
 */
object JobInvokeUtil {
    /**
     * 执行方法
     *
     * @param sysJob 系统任务
     */
    @Throws(Exception::class)
    fun invokeMethod(sysJob: SysJob) {
        val invokeTarget = sysJob.invokeTarget
        val beanName = getBeanName(invokeTarget)
        val methodName = getMethodName(invokeTarget)
        val methodParams = getMethodParams(invokeTarget)
        if (!isValidClassName(beanName)) {
            val bean = SpringUtils.getBean<Any>(beanName)
            invokeMethod(bean, methodName, methodParams)
        } else {
            val bean = Class.forName(beanName).getDeclaredConstructor().newInstance()
            invokeMethod(bean, methodName, methodParams)
        }
    }

    /**
     * 调用任务方法
     *
     * @param bean 目标对象
     * @param methodName 方法名称
     * @param methodParams 方法参数
     */
    @Throws(NoSuchMethodException::class, SecurityException::class, IllegalAccessException::class, IllegalArgumentException::class, InvocationTargetException::class)
    private fun invokeMethod(bean: Any, methodName: String, methodParams: List<Array<Any>>?) {
        if (methodParams != null) {
            if (MyStringUtils.isNotNull(methodParams) && methodParams.isNotEmpty()) {
                val method = bean.javaClass.getMethod(methodName, *getMethodParamsType(methodParams))
                method.invoke(bean, *getMethodParamsValue(methodParams))
            } else {
                val method = bean.javaClass.getMethod(methodName)
                method.invoke(bean)
            }
        }
    }

    /**
     * 校验是否为为class包名
     *
     * @param invokeTarget 名称
     * @return true是 false否
     */
    fun isValidClassName(invokeTarget: String?): Boolean {
        return StringUtils.countMatches(invokeTarget, ".") > 1
    }

    /**
     * 获取bean名称
     *
     * @param invokeTarget 目标字符串
     * @return bean名称
     */
    fun getBeanName(invokeTarget: String?): String {
        val beanName: String = StringUtils.substringBefore(invokeTarget, "(")
        return StringUtils.substringBeforeLast(beanName, ".")
    }

    /**
     * 获取bean方法
     *
     * @param invokeTarget 目标字符串
     * @return method方法
     */
    fun getMethodName(invokeTarget: String?): String {
        val methodName: String = StringUtils.substringBefore(invokeTarget, "(")
        return StringUtils.substringAfterLast(methodName, ".")
    }

    /**
     * 获取method方法参数相关列表
     *
     * @param invokeTarget 目标字符串
     * @return method方法相关参数列表
     */
    fun getMethodParams(invokeTarget: String?): List<Array<Any>>? {
        val methodStr: String = StringUtils.substringBetween(invokeTarget, "(", ")")
        if (MyStringUtils.isEmpty(methodStr)) {
            return null
        }
        val methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        val classs: MutableList<Array<Any>> = LinkedList()
        for (i in methodParams.indices) {
            val str: String = StringUtils.trimToEmpty(methodParams[i])
            // String字符串类型，以'或"开头
            if (StringUtils.startsWithAny(str, "'", "\"")) {
                classs.add(arrayOf(MyStringUtils.mySubstring(str, 1, str.length - 1), String::class.java))
            } else if ("true".equals(str, ignoreCase = true) || "false".equals(str, ignoreCase = true)) {
                classs.add(arrayOf(java.lang.Boolean.valueOf(str), Boolean::class.java))
            } else if (StringUtils.endsWith(str, "L")) {
                classs.add(arrayOf(java.lang.Long.valueOf(MyStringUtils.mySubstring(str, 0, str.length - 1)), Long::class.java))
            } else if (StringUtils.endsWith(str, "D")) {
                classs.add(arrayOf(java.lang.Double.valueOf(MyStringUtils.mySubstring(str, 0, str.length - 1)), Double::class.java))
            } else {
                classs.add(arrayOf(Integer.valueOf(str), Int::class.java))
            }
        }
        return classs
    }

    /**
     * 获取参数类型
     *
     * @param methodParams 参数相关列表
     * @return 参数类型列表
     */
    fun getMethodParamsType(methodParams: List<Array<Any>>?): Array<Class<*>?> {
        val classs: Array<Class<*>?> = arrayOfNulls(methodParams!!.size)
        for ((index, os) in methodParams.withIndex()) {
            classs[index] = os[1] as Class<*>
        }
        return classs
    }

    /**
     * 获取参数值
     *
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    fun getMethodParamsValue(methodParams: List<Array<Any>>?): Array<Any?> {
        val classs = arrayOfNulls<Any>(methodParams!!.size)
        for ((index, os) in methodParams.withIndex()) {
            classs[index] = os[0]
        }
        return classs
    }
}
